#include<iostream>
#include<string>
#include<cstdio>
#include<unistd.h>
// #include<pthread.h>               //这个是调用   pthread_create  的头文件
// #include<thread>                  //这个是C++ 11的头文件
#include<pthread.h>   
#include<cstring>     
#include<vector>          

// //新线程的入口函数，所有的代码编译出来就是一组虚拟地址
// void *threadrun(void *args)    //函数名随意，返回值是 void*，参数是 void*（函数指针）
// {
//     std::string name = (const char*)args;     //强转成为指针
//     while(true)
//     {
//         sleep(1);
//         std::cout<<"我是新的线程: name: "<<name<<",pid: "<<getpid()<<std::endl;
//     }
//     return nullptr;
// }


// //main函数 就是另外一组虚拟地址表示的代码和数据
// int main()
// {
//     //创建多线程
//     pthread_t tid;
//     pthread_create(&tid,nullptr,threadrun,(void*)"thread-1");     
//     //调用成功会就创建出来多线程，新线程就会去执行threadrun函数了，主线程继续向下运行

//     while(true)
//     {
//         std::cout<<"我是主线程。。。"<<",pid是： "<<getpid()<<std::endl;
//         sleep(1);
//     }

//     return 0;
// }


/////////////////    注意：上面的情况，是需要在make中链接第三方库的(不然会报编译错误)  -lpthread  /////////////////


//对于C++ 11 也引入了多线程     头文件#include<thread>      C++11创建多线程
//但是！！！要注意：C++ 11的多线程，在Linux下，本质上是封装了pthread库！！！     如果没有链接第三方库（-lpthread  还是会报错）
// void hello()
// {
//     while(true)
//     {
//         std::cout<<"这是新线程: hello world,pid: "<<getpid()<<std::endl;
//         sleep(1);
//     }
// }


// int main()
// {
//     std::thread t(hello);        //C++ 11的创建线程的方法：std::thread 函数名(函数指针)
//     while(true)
//     {
//         std::cout<<"我是主线程 ..."<<",pid:"<<getpid()<<std::endl;
//         sleep(1);
//     }    
//     t.join();
//     return 0;
// }


////////////////  注意：上面是C++11 方式  //////////////////


// void showid(pthread_t &tid)
// {
//     printf("tid = 0x%lx\n",tid);   //pthread_t 是一个长整数;打印出来是线程id，不是lwp，因为对其做了封装，但是过长，一般用十六进制进行打印
// }

// std::string FormatId(const pthread_t &tid)
// {
//     char id[64];      //转化成为16进制的字符串数
//     snprintf(id,sizeof(id),"0x%lx",tid);  //第一个参数：要写到的内存缓冲区中    第二个参数：大小   第三个：格式   第四个：写哪个内容
//     //把内容格式化到id里面
//     return id;      //返回整数的16进制数   会把其当做字符串
// }

// void *routine(void *args)    //返回值 void* 类型
// {
//     //static_cast 强转成为字符串，拷贝到字符串中
//     std::string name = static_cast<const char*>(args);    //static_cast是类型转换操作符
//     pthread_t tid = pthread_self();      //这个接口 pthread_self 是获取tid的  接口
//     int cnt = 5;
//     while(cnt)
//     {
//         std::cout<<"我是新线程：我的名字是："<<name<<"  我的ID是："<<FormatId(tid)<<std::endl;
//         sleep(1);
//         cnt--;
//     }
//     // return nullptr;     //这里的返回值可以是   return （void*）100;      可以暂时表示：该线程退出时的退出码 
//     return (void*)100;     //更改返回值  （void*）100
// }

// int main()
// {
//     pthread_t tid;
//     //线程创建时把对应的参数传递给routine ---> (void*)"thread-1",新线程运行时，它的参数就会被设置为传入的参数
//     //pthread_create 底层调用完线程，给线程指定的方法时（routine），然后进行回调。回调时传入的参数就是(void*)"thread-1"
//     int n = pthread_create(&tid,nullptr,routine,(void*)"thread-1");  //这里传递了 thread-1 字符串，传过之后
//     (void)n;
//     showid(tid);
    
//     int cnt = 5;
//     while(cnt)
//     {
//         //注意：这里的pthread_self是不能被修改的   所以在上面的FormatId中加上const修饰    查过之后把返回值直接格式化到FormatId中
//         //返回值是常引用    返回值是临时数据
//         std::cout<<"我是main主线程：我的名字是：main thread"<<"  我的Id是： "<<FormatId(pthread_self())<<std::endl;
//         sleep(1);
//         cnt--;
//     }

//     //对于上面的routine，返回值是void* 类型，这里的pthread_join第二参数是void** retval    void**类型
//     // pthread_join(tid,nullptr);      //等待创建好的新线程   什么都不做       也就是会在五秒内都等待这个新线程

     
//     //// 上面对于routine返回值做了更改  这里的pthread_join也就需要更改！ ////
//     void *ret = nullptr;     //ret也是一个变量，也有空间

// // join这里只有收到退出码，没有异常信号，因为等待目标进程一旦异常，整个进程都退出，包括main线程，所以对于join异常，没有意义，也看不到
// // join都是基于：线程健康跑完的情况，不需要处理异常信号，因为异常信号是进程处理中的话题
//     pthread_join(tid,&ret);
//     std::cout<<"ret is: "<< (long long int)ret << std::endl;     //最终输出：ret is：100   主线程可以获得分线程的退出码的

//     return 0;
// }




////////////////  测试传值 ---> 传对象    以及退出  //////////////////
//构建class类，class Task
// class Task
// {
// public:
//     Task(int a,int b)
//         :_a(a),_b(b){}

//     int func()
//     {
//         return _a + _b;
//     }
    
//     ~Task(){}

// private:
//     int _a;
//     int _b;
// };


// class Result
// {
// public:
//     Result(int result):_result(result){}
    
//     int GetResult()
//     {
//         return _result;
//     }

//     ~Result(){}
// private:
//     int _result;
// };


// //对于 void* p ---> 他是需要开辟空间的（可以在pthread_join中获取）
// void *routine(void *args)
// {
//     Task *t = static_cast<Task*>(args);
//     sleep(1);    //模拟执行
//     Result *res = new Result(t->func()); //t->func 是获得结果
//    sleep(1);
   
// //    return res;    //返回结果    返回的是一个Result对象的地址

//    pthread_exit(res);       //类似退出码，和上面的return res效果一致
// }

// int main()
// {   
//     pthread_t tid; 
//     Task *t = new Task(10,20);     //把任务对象构建出来    堆上申请空间
//     pthread_create(&tid,nullptr,routine,(void*)t);     //把t任务传进来
//     int cnt = 5;
//     while(cnt--)
//     {
//         std::cout<< "main线程名字: "<<std::endl;
//         sleep(1);
//     }

//     Result *ret = nullptr;     
//     pthread_join(tid,(void**)&ret); 
//     int n = ret->GetResult();

//     std::cout<<"新线程结束，运行结果："<< n <<std::endl; 
    
//     delete t;
//     delete ret;
//     return 0;
// }



#if 0
/////////////////////////// 测试  pthread_cancel  //////////////////////////////
//如果线程没有被分离,新线程会自行运行，自行结束，pthread_join 会拿到退出结果，获得返回值，返回值就是0
//一旦分离，就不能被join了！就会失败
class Result
{
public:
    Result(int result):_result(result){}
    int GetResult(){ return _result; }
    ~Result(){}
private:
    int _result;
};

class Task
{
public:
    Task(int a,int b)
        :_a(a),_b(b)
    {}

    int Execute()
    { 
        return _a + _b; 
    }

    ~Task(){}

private:
    int _a;
    int _b;
};


void *routine(void *args)
{
    int cnt = 5;
    while(cnt--)
    {
        // std::cout<<"main 线程名字： "<<std::endl;
        std::cout<<"新线程名字： "<<std::endl;
        sleep(1);
    }
    return nullptr;
}

int main()
{
    pthread_t tid;
    // Task *t = new Task(10,20);
    pthread_create(&tid,nullptr,routine,(void*)"thread-1");

    // pthread_cancel(tid);
    // std::cout<<"新线程被取消！"<<std::endl;


    //变成 分离线程   detach
    // pthread_detach(tid);      //把线程分离   这个是主线程给新线程分离了

    
    //自己给自己分离
    pthread_detach(pthread_self());     //pthread_self()   获得自己的线程id，然后用detach把自己进行分离

    std::cout<<"新线程被分离"<<std::endl;

    int cnt = 5;
    while(cnt--)
    {
        std::cout<<"main 线程名字： "<<std::endl;
        sleep(1);
    }

    int n = pthread_join(tid,nullptr);     //用n进行接收  什么都不管就用nullptr
    if(n!=0)
    {
        std::cout<<"pthread_join error: "<<strerror(n) <<std::endl;     //strerror 是c库提供  #include<cstring>
    }


    // sleep(3);
    // pthread_cancel(tid);
    // std::cout<<"新线程被取消了！"<<std::endl;

    // void *ret = nullptr;        //即使是nullptr 也会申请8字节空间
    // pthread_join(tid,&ret);
    // std::cout<<"新线程结束，运行结果是： "<< (long long)ret <<std::endl;
    // //一个线程非正常退出，被主线程给取消了，退出的结果就是保存在ret中的结果，想拿到对应的内容，使用pthread_join

    return 0;
}


#endif






/////////////////////  创建多线程  ////////////////////////////
const int num = 10;     //创建10个线程

void *routine(void *args)
{
    std::string name = static_cast<const char*>(args);
    int cnt = 5;
    while(cnt--)
    {
        std::cout<<"新线程名字： "<< name <<std::endl;
        sleep(1);
    }
    return nullptr;
}

int main()
{
    std::vector<pthread_t> tids;
    for(int i = 0;i<num;i++)
    {
        pthread_t tid;

        char id[64];
    //如果是printf就会是   从thread-1 ---> thread-9      但是给了缓冲区，把后面格式化输出的字符串写到缓冲区里         
        snprintf(id,sizeof(id),"thread-%d",i);     
    //把routine都传进去，所有的子线程都执行routine
        int n = pthread_create(&tid,nullptr,routine,id);    //对应的tid，线程属性，线程间的函数，线程要传递的参数（这里把线程名传进去）
        //只有主线程能到这
        if(n == 0)
            tids.push_back(tid);    //因为 tid 在push成功之后，下次都会在循环重定义
        else
            continue;

    }

    for(int i = 0;i < num;i++)
    {
        int n = pthread_join(tids[i],nullptr);
        if(n == 0)
        {
            std::cout<<"等待线程成功！！"<<std::endl;
        }
    }

    return 0;    //线程如果必须要进行等待，那就需要一个一个等待！    如果，不想一个个等待，那就pthread_detach(thread_self())
}



















